package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eastfair.builder.vo.ExhibitorVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.exception.BizException;
import com.eastfair.projectcore.enumeration.MenuAffiliationEnum;
import com.eastfair.venueservice.dto.ExhibitionSettlementDTO;
import com.eastfair.venueservice.dto.ServiceOrderDTO;
import com.eastfair.venueservice.entity.ServiceOrder;
import com.eastfair.venueservice.entity.ServiceProvider;
import com.eastfair.venueservice.enumeration.ServiceOrderOrderSourceEnum;
import com.eastfair.venueservice.enumeration.ServiceOrderOrderStatusEnum;
import com.eastfair.venueservice.enumeration.ServiceOrderPayStatusEnum;
import com.eastfair.venueservice.enumeration.ServiceProviderTypeEnum;
import com.eastfair.venueservice.exceptioncode.VenueServiceExceptionCode;
import com.eastfair.venueservice.service.*;
import com.eastfair.venueservice.vo.ExhibitionSettlementVO;
import com.eastfair.venueservice.vo.ServiceBookingVO;
import com.eastfair.venueservice.vo.ServiceOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 场馆报修订单 service.
 *
 * @author dqq
 * @date 2023 /4/26
 */
@Service
@Slf4j
public class VenueRepairServiceOrderServiceImpl implements VenueRepairServiceOrderService {

    @Resource
    private VenueManageServiceOrderService venueManageServiceOrderService;

    @Resource
    private ServiceOrderService serviceOrderService;

    @Resource
    private RepairReportService repairReportService;

    @Resource
    private ServiceProviderService serviceProviderService;

    @Resource
    private ServiceProviderSpaceService serviceProviderSpaceService;

    @Resource
    private ServiceBookingService serviceBookingService;

    @Resource
    private VenueManageBuilderRepairReportService venueManageBuilderRepairReportService;

    @Override
    public List<ServiceOrderVO> listForVenueRepairOrderSettlement(ServiceOrderDTO query) {
        log.info("listForVenueRepairOrderSettlement - 展会ID查询需结算的场馆报修订单, query={}", query);
        // 如果是主场结算，则查询主场负责的搭建商
        ServiceProvider serviceProvider = serviceProviderService.getById(query.getCompanyId());
        if (serviceProvider != null && ServiceProviderTypeEnum.HOME_SERVICE_PROVIDER.eq(serviceProvider.getServiceProviderType())) {
            // 查询主场在展会中负责的搭建商
            List<ExhibitorVO> builderList = serviceProviderService.listBuilderByHomeId(query.getCompanyId(), query.getExhibitionManageId());
            if (builderList == null || builderList.isEmpty()) {
                return Collections.emptyList();
            }
            List<Long> builderIdList = builderList
                    .stream()
                    .map(ExhibitorVO::getBuilderId)
                    .collect(Collectors.toList());
            query.setCompanyIdList(builderIdList);
            query.setCompanyId(null);
        }
        // 查询展会下待结算的报修订单
        QueryWrapper<ServiceOrder> queryWrapper = createVenueRepairOrderForSettlement(query);
        List<ServiceOrder> venueRepairOrderList = serviceOrderService.list(queryWrapper);
        if (venueRepairOrderList == null || venueRepairOrderList.isEmpty()) {
            return Collections.emptyList();
        }
        return serviceOrderService.packageServiceBookingList(venueRepairOrderList);
    }

    @Override
    public ExhibitionSettlementVO getVenueRepairSettlement(ExhibitionSettlementDTO query) {
        // 查询展会下待结算的订单列表
        ServiceOrderDTO orderQuery = new ServiceOrderDTO();
        orderQuery.setExhibitionManageId(query.getExhibitionManageId());
        orderQuery.setCompanyId(query.getCompanyId());
        List<ServiceOrderVO> venueRepairOrderList = listForVenueRepairOrderSettlement(orderQuery);
        if (venueRepairOrderList == null || venueRepairOrderList.isEmpty()) {
            return null;
        }
        ExhibitionSettlementVO exhibitionSettlementVO = ServiceOrderService.calculateExhibitionSettlement(venueRepairOrderList);
        return exhibitionSettlementVO;
    }

    @Override
    public ServiceOrderVO getVOByOrderNumber(String orderNumber) {
        return venueManageServiceOrderService.getVOByOrderNumber(orderNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder saveServiceOrderForVenue(ServiceOrderDTO serviceOrderDTO) {
        // 校验报修单是否生成了订单
        ServiceOrder existsServiceOder = serviceOrderService.getByRepairReportNumber(serviceOrderDTO.getRepairReportNumber(), ServiceOrderOrderSourceEnum.VENUE_HOME_REPAIR_ORDER);
        if (existsServiceOder != null && !ServiceOrderOrderStatusEnum.CANCEL.eq(existsServiceOder.getOrderStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_CAN_NOT_CREATE_ORDER.getCode(), "报修已预定服务，不可再预定");
        }
        serviceOrderDTO.setPayStatus(ServiceOrderPayStatusEnum.SETTLE_AFTER_EXHIBITION);
        serviceOrderDTO.setOrderSource(ServiceOrderOrderSourceEnum.VENUE_HOME_REPAIR_ORDER);
        serviceOrderDTO.setBelongSystem(MenuAffiliationEnum.P_COMPOSITE_VENUE.getCode());
        ServiceOrder serviceOrder = venueManageServiceOrderService.saveServiceOrderForVenue(serviceOrderDTO);
        // 更新报修单为已预定服务
        repairReportService.updateIsBookService(serviceOrderDTO.getRepairReportNumber(), BusinessConstant.YES);
        return serviceOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder updateServiceOrder(ServiceOrderDTO serviceOrderDTO) {
        return venueManageServiceOrderService.updateServiceOrder(serviceOrderDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitServiceOrder(String orderNumber) {
        venueManageServiceOrderService.submitServiceOrder(orderNumber);
        // 更新主场需赔付场馆金额
        updateBuilderRepairReportCompensateVenueAmount(orderNumber);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelServiceOrder(String orderNumber) {
        venueManageServiceOrderService.cancelServiceOrder(orderNumber);
        // 更新报修申请为未预定服务
        updateRepairReportIsBookService(orderNumber, BusinessConstant.NO);
        // 更新搭建商报修申请需赔付场馆金额为0
        cancelBuilderRepairReportCompensateVenueAmount(orderNumber);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public boolean cancelTimeoutNotPayServiceOrder(String orderNumber) {
        return cancelServiceOrder(orderNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateRepairReportIsBookService(String orderNumber, Integer isBookService) {
        log.info("updateRepairReportIsBookService - 更新报修单是否预定服务, orderNumber={}, isBookService={}", orderNumber, isBookService);
        ServiceOrder serviceOrder = serviceOrderService.getByOrderNumber(orderNumber);
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST.getCode(), "订单不存在");
        }
        String repairReportNumber = serviceOrder.getRepairReportNumber();
        return repairReportService.updateIsBookService(repairReportNumber, isBookService);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBuilderRepairReportCompensateVenueAmount(String orderNumber) {
        log.info("updateBuilderRepairReportCompensateVenueAmount - 更新搭建商报修申请的需赔付场馆金额为，场馆为主场下的报修订单金额, orderNumber={}", orderNumber);
        ServiceOrder serviceOrder = serviceOrderService.getByOrderNumber(orderNumber);
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST.getCode(), "订单不存在");
        }
        String repairReportNumber = serviceOrder.getRepairReportNumber();
        return venueManageBuilderRepairReportService.updateCompensateVenueAmount(repairReportNumber, serviceOrder.getShouldPayAmount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelBuilderRepairReportCompensateVenueAmount(String orderNumber) {
        log.info("cancelBuilderRepairReportCompensateVenueAmount - 取消场馆为主场下的订单，搭建商报修申请需赔付场馆金额清0, orderNumber={}", orderNumber);
        ServiceOrder serviceOrder = serviceOrderService.getByOrderNumber(orderNumber);
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST.getCode(), "订单不存在");
        }
        String repairReportNumber = serviceOrder.getRepairReportNumber();
        return venueManageBuilderRepairReportService.updateCompensateVenueAmount(repairReportNumber, BigDecimal.ZERO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean payServiceOrder(ServiceOrderDTO serviceOrderDTO) {
        return venueManageServiceOrderService.payServiceOrder(serviceOrderDTO);
    }

    /**
     * 场馆报修结算查询.
     *
     * @param query the query
     * @return the query wrapper
     */
    public static QueryWrapper<ServiceOrder> createVenueRepairOrderForSettlement(ServiceOrderDTO query) {
        QueryWrapper<ServiceOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ServiceOrder::getIsDeleted, BusinessConstant.DELETE_NO)
                .in(ServiceOrder::getBelongSystem, MenuAffiliationEnum.P_COMPOSITE_VENUE.getCode())
                .in(ServiceOrder::getOrderSource, ServiceOrderOrderSourceEnum.VENUE_HOME_REPAIR_ORDER)
                .ne(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.NOT_SUBMIT)
                .ne(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.CANCEL)
                .eq(query.getExhibitionManageId() != null, ServiceOrder::getExhibitionManageId, query.getExhibitionManageId())
                .eq(query.getCompanyId() != null, ServiceOrder::getCompanyId, query.getCompanyId())
                .in(query.getCompanyIdList() != null && !query.getCompanyIdList().isEmpty(), ServiceOrder::getCompanyId, query.getCompanyIdList())
                .in(query.getSpaceCodeList() != null && !query.getSpaceCodeList().isEmpty(), ServiceOrder::getSpaceCode, query.getSpaceCodeList())
        ;
        return queryWrapper;
    }
}